﻿using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections.Generic;

namespace CGF
{
    public class MetadataBuilder
    {
        //忽略(不用补充)的元数据dll
        private static string[] IgnoreList =
        {
            "I18N.CJK",
            "I18N.Rare",
            "I18N.West",
            "I18N",
            "I18N.Other",
            "I18N.MidEast",
            "UnityEngine.XRModule",
            "UnityEngine.VRModule"
        };

        //IL2CPP模式打包时会对没有引用到的代码进行裁剪，导致热更程序集很多泛型无法使用（例如async/CTask<T>），
        //为了把裁剪的部分加回来，HybridCLR在打包时把被裁剪掉的代码集中到AssembliesPostIl2CppStrip目录。
        //所以必须先打包一次生成裁剪代码，然后再将裁剪代码打AB放到StreamingAssets目录，最后再一起打包
        [MenuItem("CGFramework/补充元数据 (Build后执行该命令再Build方可生效)", priority = -1030)]
        private static void BuildMetadataIntoStreamingFolder()
        {
            BuildTarget platform = EditorUserBuildSettings.activeBuildTarget;

            //补充元数据dll(泛型必备，出ab包后只放StreamingAssets里，跟apk匹配，不能做热更)
            string metadataTempPath = $"Assets/{Define.BundleFolder}/Metadata";
            if (!Directory.Exists(metadataTempPath)) Directory.CreateDirectory(metadataTempPath);
            string aotDllDir = HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(platform);
            if (!Directory.Exists(aotDllDir))
            {
                Debug.LogError($"裁剪后的AOT dll在BuildPlayer时才能生成，因此需要先构建一次游戏App后再打包。");
                return;
            }
            string[] assemblyPaths = Directory.GetFiles(aotDllDir, "*.dll");
            for (int i = 0; i < assemblyPaths.Length; i++)
            {
                string dllPath = assemblyPaths[i];
                if (!IsIgnore(dllPath))
                {
                    string fileName = System.IO.Path.GetFileName(dllPath);
                    string targetPath = $"{metadataTempPath}/{fileName}.bytes";
                    File.Copy(dllPath, targetPath, true);
                    AssetDatabase.ImportAsset(targetPath);
                }
            }
            BuildABIntoStreamingFolder(metadataTempPath, platform);
            AssetDatabase.DeleteAsset(metadataTempPath);
            AssetDatabase.Refresh();
            Debug.Log($"元数据已打包到StreamingAssets目录，请重新出包");
        }

        private static void BuildABIntoStreamingFolder(string sourcefolder, BuildTarget platform)
        {
            string abName = Define.MetadataAbName + Define.AbExtName;
            List<AssetBundleBuild> builds = new List<AssetBundleBuild>();
            AssetBundleBuild build = new AssetBundleBuild();
            build.assetBundleName = abName;
            build.assetNames = new string[] { sourcefolder };
            builds.Add(build);
            BuildPipeline.BuildAssetBundles(sourcefolder, builds.ToArray(), BuildAssetBundleOptions.None, platform);
            string streamingDir = Application.streamingAssetsPath;
            if (!Directory.Exists(streamingDir)) Directory.CreateDirectory(streamingDir);
            string targetPath = $"{streamingDir}/{abName}";
            File.Copy($"{sourcefolder}/{abName}", targetPath, true);
        }

        private static bool IsIgnore(string dllPath)
        {
            for (int i = 0; i < IgnoreList.Length; i++)
            {
                if (dllPath.EndsWith($"{IgnoreList[i]}.dll"))
                {
                    return true;
                }
            }
            return false;
        }
    }
}